package
{
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.net.FileReference;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.text.TextField;
	import flash.ui.Keyboard;
	import flash.utils.ByteArray;
	import flash.utils.getQualifiedClassName;

	public class UIEditor
	{
		internal static var stage:Stage;
		internal static var borderContainer:Sprite;
		
		private static var instance:UIEditor;
		
		[Embed(source="MyCode.swf", mimeType="application/octet-stream")]
		private var clase:Class;
		
		private var _mycode:*;
		
		private const WIDTH:int = 300;
		private const HEIGHT:int = 400;
		
		private var _txtParent:TextField;
		
		private var _container:Sprite;
		private var _title:Sprite;
		private var _list:*;
		
		private var _arrBorder:Array;
		private var _arrSelectItems:Array;
		
		private var _catch:Sprite;
		
		private var _currentDis:DisplayObject;
		private var _dis:Sprite;
		
		private var _application:ApplicationDomain;
		private var _loader:Loader;
		
		private var _init:Boolean = false;
		
		public function UIEditor()
		{
			_loader = new Loader();
			_application = new ApplicationDomain( ApplicationDomain.currentDomain );
			_loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoaded );
			_loader.loadBytes( new clase() as ByteArray, new LoaderContext(false, _application) );
		}

		private function onLoaded( e:Event ):void
		{
			init();
			_init = true;
			if( _dis != null )
			{
				edit( _dis );
			}
		}
		
		private function init():void
		{
			_arrBorder = new Array();
			_arrSelectItems = new Array();
			
			_container = new Sprite();
			
			_txtParent = new TextField();
			_txtParent.text = " ";
			_txtParent.background = true;
			_txtParent.backgroundColor = 0x999999;
			_txtParent.textColor = 0xffffff;
			_txtParent.selectable = false;
			_txtParent.multiline = false;
			_txtParent.height = _txtParent.textHeight + 4;
			_txtParent.width = WIDTH;
			
			_list = (_loader.content as Object).getList();
			_list.setSize( WIDTH-10, HEIGHT-_txtParent.height );
			
			_title = new Sprite();
			_title.graphics.beginFill( 0 );
			_title.graphics.drawRect( 0, 0, WIDTH, 20 );
			_title.graphics.endFill();
			_container.addChild( _title );
			
			_txtParent.y = _title.height;
			_container.addChild( _txtParent );
			
			_catch = new Sprite();
			_catch.graphics.beginFill(0xff0000);
			_catch.graphics.drawRect( 0, 0, 10, 20 );
			_catch.graphics.endFill();
			_container.addChild( _catch );
			_catch.addEventListener( MouseEvent.CLICK, onChange );
			
			_list.setLocation( 10, _title.height+_txtParent.height );
			
			_container.graphics.beginFill( 0xffffff );
			_container.graphics.lineStyle( 1 );
			_container.graphics.drawRect( 0, 0, WIDTH, HEIGHT+20 );
			_container.graphics.endFill();
			_container.addChild( _list );
			
			borderContainer = new Sprite();
			borderContainer.mouseChildren = false;
			
			_txtParent.doubleClickEnabled = true;
			_txtParent.addEventListener( MouseEvent.MOUSE_DOWN, onDoubleClickParent );
			_title.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown );
			_title.addEventListener( MouseEvent.MOUSE_UP, onMouseUp );
			
			borderContainer.addEventListener( MouseEvent.MOUSE_DOWN, onBorderDown );
			borderContainer.addEventListener( MouseEvent.MOUSE_UP, onBorderUp );
		}
		
		private var _selected:Boolean = false;
		private function onChange( e:Event ):void
		{
			_selected = !_selected;
			
			_catch.graphics.clear();
			_catch.graphics.beginFill( _selected?0x00ff00:0xff0000 );
			_catch.graphics.drawRect( 0, 0, 10, 20 );
			_catch.graphics.endFill();
			
			if( _selected )
			{
				stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeydown, false, int.MAX_VALUE );
			}
			else 
			{
				stage.removeEventListener( KeyboardEvent.KEY_DOWN, onKeydown, false );
			}
		}
		
		private function onKeydown( e:KeyboardEvent ):void
		{
			e.stopImmediatePropagation();
			if( _arrBorder.length==0 ) return;
			var keyCode:uint = e.keyCode;
			
			var value:int = e.shiftKey ? 10 : 1;
			var i:int;
			var b:__Border;
			switch( keyCode )
			{
			case Keyboard.LEFT:
				for( i=0; i<_arrBorder.length; i++ )
				{
					(_arrBorder[i] as __Border).dis.x -= value;
				}
				break;
			case Keyboard.RIGHT:
				for( i=0; i<_arrBorder.length; i++ )
				{
					(_arrBorder[i] as __Border).dis.x += value;
				}
				break;
			case Keyboard.DOWN:
				for( i=0; i<_arrBorder.length; i++ )
				{
					(_arrBorder[i] as __Border).dis.y += value;
				}
				break;
			case Keyboard.UP:
				for( i=0; i<_arrBorder.length; i++ )
				{
					(_arrBorder[i] as __Border).dis.y -= value;
				}
				break;
			case Keyboard.BACKSPACE:
				if( _currentDis != _dis )
				{
					changeTO( _currentDis.parent as Sprite );
				}
				break;
			}
		}
		
		private function onMouseDown( e:MouseEvent ):void
		{
			_container.startDrag();
		}
		
		private function onMouseUp( e:MouseEvent ):void
		{
			_container.stopDrag();
		}
		
		private function onBorderDown( e:MouseEvent ):void
		{
			borderContainer.startDrag();
		}
		
		private function onBorderUp( e:MouseEvent ):void
		{
			borderContainer.stopDrag();
			
			var x:int = borderContainer.x;
			var y:int = borderContainer.y;
			for( var i:int=0; i<_arrBorder.length; i++ )
			{
				(_arrBorder[i] as __Border).dis.x += x;
				(_arrBorder[i] as __Border).dis.y += y;
			}
			borderContainer.x = borderContainer.y = 0;
		}
		
		public function edit( dis:Sprite ):void
		{
			_dis = dis;
			if( !_init ) return;
			
			if( _dis.stage )
			{
				changeTO( dis );
			}
			else
			{
				dis.addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
			}
			_dis.addEventListener( Event.REMOVED_FROM_STAGE, onRemoveFromStage );
		}
		
		private function onRemoveFromStage( e:Event ):void
		{
			clear();
			if( _selected ) onChange(null);
			if( borderContainer.parent ) borderContainer.parent.removeChild( borderContainer );
			if( _container.parent ) _container.parent.removeChild( _container );
			_container.stopDrag();
		}
		
		private function onAddToStage( e:Event ):void
		{
			changeTO( _dis );
		}
		
		private function changeTO( dis:Sprite ):void
		{
			if( stage==null ) 
			{
				stage = dis.stage;
			}
			if( _container.parent==null ) stage.addChild( _container );
			if( borderContainer.parent==null ) stage.addChild( borderContainer );
			
			_txtParent.text = dis.name+ " (" + getQualifiedClassName(dis) + ")" + " : " + dis.numChildren;
			
			clear();
			var b:__Border = new __Border( dis );
			_arrBorder.push( b );
			
			_currentDis = dis;
			_list.removeAllItem();
			if( _currentDis is DisplayObjectContainer ) 
			{
				var n:int = (_currentDis as DisplayObjectContainer).numChildren;
				for( var i:int=0; i<n; i++ )
				{
					var item:DisItem = new DisItem( (_currentDis as DisplayObjectContainer).getChildAt(i) );
					if( item.dis is DisplayObjectContainer )
					{
						item.title.addEventListener( MouseEvent.DOUBLE_CLICK, onDoubleClick, false, 0, true );
					}
					item.btnEdit.addEventListener( MouseEvent.CLICK, onEditItem, false, 0, true );
					item.btnOutput.addEventListener( MouseEvent.CLICK, onOutItem, false, 0, true );
					item.addEventListener( MouseEvent.MOUSE_DOWN, onMouseItemDown, false, 0, true );
					_list.addItem( item );
				}
			}
		}
		
		private function onDoubleClickParent( e:MouseEvent ):void
		{
			if( _currentDis != _dis )
			{
				changeTO( _currentDis.parent as Sprite );
			}
		}
		
		private function onOutItem( e:MouseEvent ):void
		{
			var item:DisItem = e.currentTarget.parent as DisItem;
			var bd:BitmapData = new BitmapData( item.dis.width, item.dis.height, true, 0 );
			var rect:Rectangle = item.dis.getBounds( item.dis );
			var mt:Matrix = new Matrix();
			mt.tx = -rect.x;
			mt.ty = -rect.y;
			bd.draw( item.dis, mt );
			
			var Png:__PNGEncoder = new __PNGEncoder();
			var byte:ByteArray = Png.encode( bd );
			var fr:FileReference = new FileReference();
			fr.save( byte, item.dis.name + ".png" );
		}
		
		private function onEditItem( e:MouseEvent ):void
		{
			if( _selected ) onChange(null);
			
			var item:DisItem = e.currentTarget.parent as DisItem;
			var arr:Array = __ObjectUtils.getObjectPropertys( item.dis );
			_txtParent.text = item.dis.name + "的属性：";
			
			_currentDis = item.dis;
			_list.removeAllItem();
			for( var i:int=0; i<arr.length; i++ )
			{
				var ei:__EditItem = new __EditItem( item.dis, arr[i] );
				_list.addItem( ei );
			}
		}
		
		private function onMouseItemDown( e:MouseEvent ):void
		{
			if( !e.ctrlKey )
			{
				clear();
			}
			var item:DisItem = e.currentTarget as DisItem;
			item.selected = !item.selected;
			for( var i:int=0; i<_arrBorder.length; i++ )
			{
				if( (_arrBorder[i] as __Border).dis==item.dis )
				{
					if( !item.selected )
					{
						(_arrBorder.splice(i,1)[0] as __Border).destroy();
					}
					return;
				}
			}
			if( item.selected )
			{
				var b:__Border = new __Border( item.dis );
				_arrBorder.push( b );
				_arrSelectItems.push( item );
			}
		}
		
		private function clear():void
		{
			while( _arrBorder.length > 0 ) (_arrBorder.pop() as __Border).destroy();
			while( _arrSelectItems.length > 0 ) (_arrSelectItems.pop() as DisItem).selected = false;
		}
		
		private function onDoubleClick( e:MouseEvent ):void
		{
			var item:DisItem = e.currentTarget.parent as DisItem;
			changeTO( item.dis as Sprite );
		}
		
		public static function edit( dis:Sprite ):void
		{
			if( instance==null ) instance = new UIEditor();
			instance.edit( dis );
		}
	}
}
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.filters.GlowFilter;
import flash.text.TextField;
import flash.utils.getQualifiedClassName;

class DisItem extends Sprite
{
	private var _dis:DisplayObject;
	private var _label:TextField;
	
	public var title:Sprite;
	public var btnEdit:Sprite;
	public var btnOutput:Sprite;
	
	private var _selected:Boolean = false;
	
	public function DisItem( dis:DisplayObject )
	{
		_dis = dis;
		_label = new TextField();
		_label.textColor = 0xffffff;
		_label.filters = [new GlowFilter(0, 1, 2, 2, 5)];
		_label.text = dis.name + " (" + getQualifiedClassName(dis) + ")";
		_label.width = _label.textWidth + 4;
		_label.height = _label.textHeight + 4;
		
		title = new Sprite();
		title.mouseChildren = false;
		title.doubleClickEnabled = true;
		title.addChild( _label );
		this.addChild( title );
		
		btnEdit = new Sprite();
		btnEdit.graphics.beginFill( 0x0000ff );
		btnEdit.graphics.drawRect( _label.width + 1, 0, 20, _label.height );
		btnEdit.graphics.endFill();
		btnEdit.buttonMode = true;
		btnEdit.useHandCursor = true;
		addChild( btnEdit );
		
		btnOutput = new Sprite();
		btnOutput.graphics.beginFill( 0xff0000 );
		btnOutput.graphics.drawRect( _label.width+btnEdit.width + 2, 0, 20, _label.height );
		btnOutput.graphics.endFill();
		btnOutput.buttonMode = true;
		btnOutput.useHandCursor = true;
		addChild( btnOutput );
		
		selected = false;
	}
	
	public function set selected(value:Boolean):void
	{
		_selected = value;
		
		title.graphics.clear();
		title.graphics.beginFill( value?0x3399FF:0x333333 );
		title.graphics.drawRect( 0, 0, _label.width, _label.height );
		title.graphics.endFill();
	}
	
	public function get selected():Boolean
	{
		return _selected;
	}
	
	public function get dis():DisplayObject
	{
		return _dis;
	}
}





